﻿
package extremefx.events {
	import extremefx.extensions.isObjectEmpty;

	import flash.utils.Dictionary;

	/**
	 * @author Marcelo Volmaro
	 */
	public final class Events {
		private static var _targets:Dictionary = new Dictionary(true);
		
		private var _target:Object;
		private var _handlers:Vector.<Function>;
		
		public static function create(pTarget:Object):Events {
			var e:Events = new Events();
			e._target = pTarget;
			return e;
		}
		
		public static function add(pEvent:Events, pHandler:Function):void {
			var tgt:Object = pEvent._target; 
			if (!_targets[tgt]) {
				_targets[tgt] = new Dictionary(true);
			}
			
			var regEvents:Dictionary = _targets[tgt];  
			
			if (!regEvents[pEvent]) {
				regEvents[pEvent] = pEvent;
			}
			
			if (pEvent._handlers == null){
				pEvent._handlers = new Vector.<Function>();
			}
			
			var handlers:Vector.<Function> = pEvent._handlers;
			if (handlers.indexOf(pHandler) == -1) handlers.push(pHandler);
		}
		
		public static function remove(pEvent:Events, pHandler:Function):void {
			pEvent._remove(pHandler);
		}
		
		public static function fire(pEvent:Events, pArgs:EventArgs = null):void {
			var target:Object = pEvent._target;
			var handlers:Vector.<Function> = pEvent._handlers;
			
			if (!handlers) return;
			
			if (pArgs == null){
				pArgs = new EventArgs();
			}
			
			//create a copy, so if an event handlers modifies the event list, that modification does not gets
			//propagated until next firing...
			var s:Vector.<Function> = handlers.concat();
			pArgs._tgt = target;

			var l:uint = s.length, i:uint = 0;
			while (i < l){ 
				s[i++](pArgs);
			}
		}
		
		public static function removeAll(pTarget:Object, pEvent:Events = null):void {
			if (!_targets[pTarget]) return;
			var regEvents:Dictionary  = _targets[pTarget]; 
			
			if (pEvent == null){
				for each(var event:Events in regEvents){
					event._remove();
				}
				
			} else {
				pEvent._remove();
			}
		}
		
		private function _remove(pHandler:Function = null):void {
			if (!_targets[_target]) return;
			
			if (pHandler == null){
				_handlers.length = 0;
				
			} else {
				var idx:int = _handlers.indexOf(pHandler); 
				if (idx == -1) return;
			
				_handlers.splice(idx, 1);
			}

			if (_handlers.length == 0) {
				_handlers = null;
			}
			
			if (isObjectEmpty(_targets[_target])){
				_targets[_target] = null;
				delete _targets[_target];	
			}
		}
	}
}
